package ongd.negocio.gestion;

import java.util.ArrayList;
import ongd.negocio.sesion.ControladorSesion;
import ongd.servicios.persistencia.ControladorPersistencia;
import java.util.List;
import ongd.servicios.persistencia.exceptions.IllegalOrphanException;
import ongd.servicios.persistencia.exceptions.NonexistentEntityException;
import ongd.servicios.persistencia.exceptions.PreexistingEntityException;

/**
 * Clase abstracta que realizará ciertas operaciones comunes a los proyectos.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 */
public abstract class ControladorProyecto {

    /**
     * Objeto del tipo controlador persistencia que nos servirá para crear 
     * las instancias de las diferentes entidades.
     */
    private ControladorPersistencia contP;
    /**
     * Objeto del tipo controlador sesion que nos servirá para sabre 
     * en que sesion estamos.
     */
    private ControladorSesion contSesion;

    /**
     * Constructor de la clase.
     * @param contP controlador Persistencia
     * @param contSesion sesión en la que estamos
     */
    public ControladorProyecto(ControladorPersistencia contP, ControladorSesion contSesion) {
        this.contP = contP;
        this.contSesion = contSesion;
    }

    /**
     * Método que se encargará de crear un proyecto nuevo en la base de datos.
     * @param proyecto Proyecto que se va a crear
     * @param lista Lista de Personas de contacto que iran asociadas al proyecto
     * @return cadena informando de si se ha creado correctamente o no
     * @throws PreexistingEntityException
     * @throws Exception 
     */
    public abstract String crearProyecto(Proyecto proyecto, List<PersonaContacto> lista) throws PreexistingEntityException, Exception;

    /**
     * Método que borra un proyecto de la base de datos.
     * @param proyecto proyecto que vamsoa  borrar.
     * @return true, si el proyecto ha sido borrado correctamente.
     *          false, si el proyecto no ha sido borrado.
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException 
     */
    public abstract boolean borrarProyecto(Proyecto proyecto) throws IllegalOrphanException, NonexistentEntityException;
    
     /**
     * Método que desactiva un proyecto y pone las subvenciones que estaban pendientes a rechazadas.
     * @param proyecto que vamsoa  desactivar.
     * @return true, si se ha desactivado correctamente o false si no es así.
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    public abstract boolean desactivarProyecto(Proyecto proyecto) throws IllegalOrphanException, NonexistentEntityException, Exception;
    
    /**
     * Método que devuelve la lista de proyectos que existen en la base de datos.
     * @return lista de proyectos.
     */
    public List<Proyecto> obtenerProyectos() {
        return (List<Proyecto>) contP.obtenerEntidades(Proyecto.class);
    }

    /**
     * Método que busca un proyecto por su nombre.
     * @param nombre del proyecto que vamos a buscar.
     * @return proyecto.
     */
    public Proyecto buscarProyecto(String nombre) {       
        for (Proyecto p : obtenerProyectos()) {
            if (p.getNombre().compareTo(nombre) == 0) {
                return p;
            }
        }
        return null;
    }

    /**
     * Método que devuelve una lista con los proyectos de un mismo tipo pasado
     * por parámetro.
     * @param tipo Tipo del proyecto
     * @return proyectosTipo
     */
    public List<Proyecto> buscarProyectosTipo(String tipo) {
        //SAco la lista de proyectos de la base de datos.
        List<Proyecto> proyectos = obtenerProyectos();        
        //Saco la lista de proyectos de la base de datos.        
        List<Proyecto> proyectosTipo = new ArrayList<Proyecto>();
        //Recorreré la lista para guardar los proyectos que sean de ese tipo y que esten activos
        for (Proyecto p : proyectos) {
            if (p.getTipo().compareTo(tipo) == 0 && p.getActivo()) {
                proyectosTipo.add(p);
            }
        }
        return proyectosTipo;
    }

     /**
     * Método que devuelve una lista de proyectos del tipo pasado por parámetro que no están activos.
     * @param tipo del que queremos que sean los proyectos.
     * @return lista de proyectos no activos del tipo deseado.
     */
    public List<Proyecto> buscarProyectosDesactivadosTipo(String tipo){
        List<Proyecto> proyectosTipo= new ArrayList<Proyecto>();
        for(Proyecto p: obtenerProyectos()){
            if(p.getTipo().compareTo(tipo)==0 && !p.getActivo()){
                proyectosTipo.add(p);
            }
        }
        return proyectosTipo;
    }
    
    /**
     * Método que crea las personas de contacto guardadas en la lista.
     * @param personasContacto Lista de personas que vamos a guardar
     * @param proyecto Proyecto al que pertenecen las personas
     * @throws PreexistingEntityException
     * @throws Exception 
     */
    public void crearPersonasContacto(List<PersonaContacto> personasContacto, Proyecto proyecto) throws PreexistingEntityException, Exception {
        PersonaContactoPK clave;
        int i = 1;
        for (PersonaContacto persCont : personasContacto) {
            clave = new PersonaContactoPK(i, proyecto.getIdProyecto());
            persCont.setPersonaContactoPK(clave);
            persCont.setProyecto(proyecto);
            contP.crearEntidad(persCont);
            i++;
        }
    }

    /**
     * Método que edita un proyecto si este existe.
     * @param proyecto proyecto que vamso a editar.
     * @param personasContacto lista de personas nueva.
     * @param modificada variable que indica si hemos modificado alguna persona de contacto.
     * @param borrar variable que indica si tenemos que borrar toda la lista y volverla a crear.
     * @return true, si se ha editado correctamente
     *          false, si no se ha editado porque no existía.
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    public boolean editarProyecto(Proyecto proyecto, List<PersonaContacto> personasContacto, boolean modificada, boolean borrar) throws IllegalOrphanException, NonexistentEntityException, Exception {
//        //Si el proyecto existe lo editamos
//        if (getContP().obtenerEntidad(Proyecto.class, proyecto.getIdProyecto()) != null) {
        //Miramos si tienen todos los datos obligatorios.
        if(proyecto.getNombre()!=null && proyecto.getPais()!=null && proyecto.getResponsableONGD()!=null){
            //Comprobamos que las personas tengan datos
            for(PersonaContacto p: personasContacto){
                if(p.getNombre()==null || p.getDireccion()==null || p.getCargo()==null || p.getTelefono1()==null){
                    return false;
                }
            }
            //Inicio la transacción
            contP.iniciarTransaccion();
            //Miramos si la lista de personasC es de tamaño diferente y sabremos si hemos borrado o añadido alguna
            if(borrar){
                if(borrarPersonasContacto(proyecto.getPersonaContactoList())){
                    contP.terminarTransaccion();
                    contP.iniciarTransaccion();
                    crearPersonasContacto(personasContacto, proyecto);
                }
            }else{
                if(modificada){
                    editarPersonasContacto(personasContacto);
                }
            }
            getContP().editarEntidad(proyecto);
            //Finalizo la transacción
            contP.terminarTransaccion();
            return true;
        }
        return false;
    }
    
    /**
     * Método que vuelve a activar un proyecto.
     * @param proyecto que vamos a activar.
     * @return true, si se ha activado o false si no ha sido así.
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    public boolean activarProyecto(Proyecto proyecto) throws IllegalOrphanException, NonexistentEntityException, Exception{
        if(contP.obtenerEntidad(Proyecto.class, proyecto.getIdProyecto())!=null && !proyecto.getActivo()){
           proyecto.setActivo(true); 
           contP.editarEntidad(proyecto);
           return true;
        }
        return false;
    }

    /**
     * Método que edita una lista de personas de contacto.
     * @param personasContacto lista de personas que vamos a editar.
     * @return true, si se ha editado correctamente o false si no es así.
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    public boolean editarPersonasContacto(List<PersonaContacto> personasContacto) throws IllegalOrphanException, NonexistentEntityException, Exception {
        for (PersonaContacto p : personasContacto) {
            if (contP.obtenerEntidad(PersonaContacto.class, p.getPersonaContactoPK()) != null) {
                contP.editarEntidad(p);
            } else {
                return false;
            }
        }
        return true;
    }    

    /**
     * Metodo que borra una lista de personas de contacto.
     * @param personasContacto lista de personas de contacto que se vana  borrar.
     * @return true, si se ha borrado la lista de personas de contacto o false si no es así. 
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException 
     */
    public boolean borrarPersonasContacto(List<PersonaContacto> personasContacto) throws IllegalOrphanException, NonexistentEntityException {
        for (int i = personasContacto.size() - 1; i >= 0; i--) {
            if (contP.obtenerEntidad(PersonaContacto.class, personasContacto.get(i).getPersonaContactoPK()) != null) {
                contP.destroyEntidad(PersonaContacto.class, personasContacto.get(i).getPersonaContactoPK());
            } else {
                return false;
            }
        }
        return true;
    }

    /**
     * Método que devuelve un objeto del tipo ControladorPersistencia.
     * @return contP
     * @see #setContP
     */
    public ControladorPersistencia getContP() {
        return contP;
    }

    /**
     * Método que establece un objeto del tipo ControladorPersistencia.
     * @param contP Nuevo valor de la variable
     * @see #getContP
     */
    public void setContP(ControladorPersistencia contP) {
        this.contP = contP;
    }

    /**
     * Método que devuelve un objeto del tipo ControladorSesion.
     * @return contSesion
     * @see #setContSesion
     */
    public ControladorSesion getContSesion() {
        return contSesion;
    }

    /**
     * Método que establece un objeto del tipo ControladorSesion.
     * @param contSesion Nuevo valor de la variable
     * @see #getContSesion
     */
    public void setContSesion(ControladorSesion contSesion) {
        this.contSesion = contSesion;
    }
}
